#!/usr/bin/lua

require 'pluto'

local rule_file_conf = "/secui/etc/rulefiles.conf"
Firewall = nil

-- 테이블끼리 비교: depth가 1인 경우에 한해서?
function tbl_comp(tbl_l, tbl_r)
    if #tbl_l ~= #tbl_r then
        return false
    else
        for i, v in ipairs(tbl_l) do
            if type(v) == "table" then
                if tbl_comp(v, tbl_l[i]) then
                    return false
                end
            else
                if v ~= tbl_l[i] then
                    return false
                end
            end
        end
        return true
    end
end

function build_db()
    -- 없는 경우, 정책 생성일을 찾기 위해서 archive를 검사
    -- 최신 파일부터 뒤짐. 즉 현재 정책 파일부터
    -- 언제 멈춰야 하나? 그냥 끝까지 진행하면 안 됨.
    local db = {}
    local temp_rule_storage = {}
    local curr_file_time = ""

    function Firewall_create(s)
        print("In create")
        print("nextid = ", s.nextid)
        -- 초기화
        temp_rule_storage.rule_db = { } 
        temp_rule_storage.next_id = s.nextid
        for _, v in ipairs(s.rules) do
            print("rule_id = ", v.rid)
            if temp_rule_storage.rule_db[v.rid] then
                if not (tbl_comp(temp_rule_storage.rule_db[v.rid].from, v.from)
                        and tbl_comp(temp_rule_storage.rule_db[v.rid].to, v.to)
                        and tbl_comp(temp_rule_storage.rule_db[v.rid].service, v.service)) then
                    print(string.format("Rule %d is modified", v.rid))
                    mtime = curr_file_time
                end
                temp_rule_storage.rule_db[v.rid].touched = true
            else
                temp_rule_storage.rule_db[v.rid] = { 
                    ["use"] = v.use, 
                    ["from"] = v.from,
                    ["to"] = v.to,
                    ["service"] = v.service,
                    ["ctime"] = curr_file_time,
                    ["mtime"] = curr_file_time,
                    ["touched"] = true,
                }
            end
        end
    end

    function Firewall_downdate(s)
        print("In downdate")
        temp_rule_storage.rule_db = {}
        temp_rule_storage.next_id = s.nextid
    end

    function adapt_fw4rule_to_db(db, filename)
        dofile(filename)
    end

    function rulefilesetconfig(s)
        for _, file in ipairs(s.fwv4.files) do
            if file.inuse then
                db.last_modified_time = file.time
                db.rule_filename = file.name
            end
        end
    end

    function create_rule_db(temp_storage) -- 최초로 정책 db에 정책들을 넣는다.
    end

    function downdate_rule_db(temp_storage) -- 더 오래된 흔적이 있으면 정책 생성 날짜를 더 전으로 변경
    end
    
    -- 정책 파일 리스트를 읽어들여서 현재 사용되고 있는 정책을 파악
    dofile(rule_file_conf)
    -- print("db.rule_filename = ", db.rule_filename)
    
    -- 현재 정책 파일로부터 rule_db를 생성
    Firewall = Firewall_create
    dofile(db.rule_filename)
    --print("temp_rule_storage = ", temp_rule_storage)
    --for k, v in pairs(temp_rule_storage) do
    --    print(k, v)
    --end
    create_rule_db(temp_rule_storage)

    -- archive directory에서 파일을 하나씩 적용해서 rule_db의 생성일을 산출해 냄.
    fwrule_archive = "/var/log/secui/archive/fwrules"
    Firewall = Firewall_downdate
    f = io.popen(string.format("ls -t %s", fwrule_archive), "r")
    for line in f:lines() do
        
        dofile(string.format("%s/%s", fwrule_archive, line))
    end
    return db
end

function check_if_rule_changed(db)
    local res = false
    function rulefilesetconfig(s)
        for _, file in ipairs(s.fwv4.files) do
            if file.inuse then
                if db.rule_filename ~= file.name 
                    or db.last_modified_time ~= file.time then
                    db.rule_filename = file.name
                    db.last_modified_time = file.time
                    res = true
                end
            end
        end
    end
    dofile(rule_file_conf)
    return res, db
end

-- 먼저 정책 DB가 있는지 검사
db_filename = "/var/tmp/secui/rule_db_fw4.plu"

local changed = false
local f = io.open(db_filename, "rb")
if f then
    print("File exist")
    local buf = f:read("*a")
    f:close()
    -- 플루토로 로드
    db = pluto.unpersist({}, buf)
    for k, v in pairs(db) do
        print(k, v)
    end
    -- 정책 파일의 생성시간이랑 비교
    changed, db = check_if_rule_changed(db)
    print("Changed = ", changed)
    print("db = ", db)
    for k, v in pairs(db) do
        print(k, v)
    end
else
    print("File not exist")
    db = build_db() -- 없으면 만들고...
    changed = true  -- 새로 만들었으니 무조건 바뀌었고....
end

if changed then
    -- 플루토로 저장
    local buf = pluto.persist({}, db)
    if buf then
        local outfile = io.open(db_filename, "wb")
        if outfile then
            outfile:write(buf)
            outfile:close()
        end
    end
end